#include "ds/stringutils.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* Local scope */
static void SU_calclen ( string * );

static void
SU_calclen ( string * str )
{
	size_t i = 0;
	for ( ; str->s[i] != '\0'; ++i )
		str->length = i;

	str->length++;
}

/* Global scope */
void
SU_construct ( string * str, size_t size )
{
	str->bytes = size;
	str->length = 0;
	str->s = calloc( 1, str->bytes );
	str->s[0] = '\0';
}

string *
SU_simple ( char * input )
{
	string * str = calloc( 1, sizeof(string) );
	str->bytes = strlen(input) + 1;
	str->s = calloc( 1, str->bytes );
	memcpy( str->s, input, str->bytes );
	str->s[str->bytes - 1] = '\0';
	str->length = str->bytes;

	return str;
}

string *
SU_copy ( string * instr )
{
	string * str = calloc( 1, sizeof(string) );
	str->length = instr->length + 1;
	str->bytes = str->length;
	str->s = calloc( 1, str->length );
	snprintf( str->s, str->length, "%s", instr->s );

	return str;
}

string *
SU_new ( size_t size )
{
	string * str = calloc( 1, sizeof(string) );
	SU_construct( str, size );

	return str;
}

void
SU_free ( string * str )
{
	if ( str == NULL )
		return;

	if ( str->s != NULL )
		free(str->s);

	free(str);
}

void
SU_set ( string * str, const char * fmt, ... )
{
	/* Similar to sprintf(), but boundaries are automatically managed. */
	va_list args;
	va_start( args, fmt );
	vsnprintf( str->s, str->bytes, fmt, args );
	va_end(args);

	SU_calclen(str);
}

void
SU_cat ( string * str, const char * fmt, ... )
{
	/* Similar to strcat(), but boundaries are automatically managed. */
	string * tmp = SU_new(str->bytes);

	va_list args;
	va_start( args, fmt );
	vsnprintf( tmp->s, tmp->bytes, fmt, args );
	va_end(args);

	strncat( str->s, tmp->s, str->bytes );
	SU_free(tmp);
	SU_calclen(str);
}

void
SU_fit_with_trunk ( string * dst, string * src, const char * cutoff )
{
	/* Tries to fit content of `src` into `dst`. If `dst` is smaller than `src` then put
	 * `cutoff` at the end of `src`. String `src` will not change its' size. */

	if ( dst == NULL || src == NULL )
		return;

	if ( dst->bytes >= src->length )
	{
		SU_set( dst, src->s );
		return;
	}

	SU_set( dst, "%s", src->s );

	size_t cutofflen = strlen(cutoff);
	dst->s[dst->length - cutofflen] = '\0';
	SU_calclen(dst);
	SU_cat( dst, "%s", cutoff );
}
